<script lang="ts">
	import { onMount, onDestroy } from 'svelte'
	import { Chart, registerables, type FinancialDataPoint } from 'chart.js/auto'
	import 'chartjs-adapter-luxon'
	import 'chartjs-adapter-date-fns' // 这个一定要引入，不然[chartjs-chart-financial]会报错
	import 'chartjs-chart-financial'
	import { CandlestickElement, CandlestickController } from 'chartjs-chart-financial'
	import { DateTime } from 'luxon'
	import zoomPlugin from 'chartjs-plugin-zoom'
	import type {
		IndicatorGroupKey,
		KlineFlat,
		TradeOrder,
		TradeBot,
		MaLineGroupKey,
	} from './bindings'
	import { formatDate } from '$lib'

	import {
		calculateTOrderBackgroundColor,
		calculateVolumeBackgroundColor,
		calculateVolumeBorderColor,
		formatNumberToString,
		handleChartMouseMove,
		updateAxisScale,
		updateIndicatorChartPart,
		updateYPriceAxisScale,
		upsertChartLsma,
		upsertChartMa,
	} from '$lib/FudaChartApi.js'

	Chart.register(CandlestickElement, CandlestickController, zoomPlugin, ...registerables)

	export let klines: KlineFlat[]
	export let trade_bot: TradeBot
	export let trade_orders: TradeOrder[]

	let candleChart: Chart
	let candleCanvas: HTMLCanvasElement
	let indicatorChart: Chart
	let indicatorCanvas: HTMLCanvasElement

	onMount(() => {
		initializeTooltip()

		// console.log('(TBotChart.svelte) trade_bot', trade_bot)
		// console.log('(TBotChart.svelte) trade_orders', trade_orders)
		// console.log('(TBotChart.svelte) klines', klines)

		// <candleChart>
		let volumes = klines.map((kline) => ({
			x: DateTime.fromISO(kline.klts).setZone('utc').valueOf(),
			y: Number(kline.volume),
			o: kline.open,
			h: kline.high,
			l: kline.low,
			c: kline.close,
		}))

		let torders = trade_orders
			.filter((o) => o.klts != null)
			.map((order) => ({
				x: DateTime.fromISO(order.klts || '2000-01-01T00:00:00Z')
					.setZone('utc')
					.valueOf(),
				y: Number(order.kl_volume),
				r: 5,
				order_type: order.order_type,
				o: 0,
				h: 0,
				l: 0,
				c: 0,
			}))
		console.log('(TBotChart.svelte) torders=', torders)
		// Prices data
		let prices: FinancialDataPoint[] = klines.map((kline) => ({
			x: DateTime.fromISO(kline.klts).setZone('utc').valueOf(),
			o: kline.open,
			h: kline.high,
			l: kline.low,
			c: kline.close,
		}))

		candleChart = new Chart(candleCanvas, {
			data: {
				datasets: [
					{
						label: 'Volume',
						type: 'bar' as const,
						data: volumes,
						yAxisID: 'y-volume',
						backgroundColor: (context: any) => calculateVolumeBackgroundColor(context),
						borderColor: (context: any) => calculateVolumeBorderColor(context),
						borderWidth: 1,
						hoverBorderWidth: 6,
					},
					{
						label: 'TradeOrder',
						type: 'bubble' as const,
						data: torders,
						yAxisID: 'y-volume',
						backgroundColor: (context: any) => calculateTOrderBackgroundColor(context),
						pointStyle: 'circle',
					},
					{
						label: 'Price',
						type: 'candlestick' as const,
						data: prices,
						yAxisID: 'y-price',
						backgroundColors: {
							up: 'rgba(255, 0, 0, 0.1)', // Semi-transparent red for price up
							down: 'rgba(0, 255, 0, 0.1)', // Semi-transparent green for price down
							unchanged: 'rgba(128, 128, 128, 0.1)', // Semi-transparent gray for unchanged
						},
						borderColors: {
							up: '#FF0000', // Red border for price up
							down: '#00FF00', // Green border for price down
							unchanged: 'gray', // Optional border color for unchanged
						},
						borderWidth: 1,
						hoverBorderWidth: 6,
					},
				],
			},
			options: {
				animation: false,
				spanGaps: true, // enable for all datasets
				responsive: true,
				maintainAspectRatio: false,
				scales: {
					'y-volume': {
						type: 'linear' as const,
						position: 'left' as const,
						// display: false, // Add this to hide the scale initially
						grid: {
							lineWidth: function (context: any) {
								if (
									context.tick &&
									typeof context.tick.value !== 'undefined' &&
									context.tick.value === context.scale.min
								) {
									return 3
								}
								return 1
							},
						},
						ticks: {
							callback: function (value: number | string): any {
								// Format price axis labels
								return formatNumberToString(Number(value))
							},
						},
						stack: 'candle',
						stackWeight: 1,
						beginAtZero: false,
						grace: '1%', // Optional: Adds a bit of padding around min/max
					},
					'y-price': {
						type: 'linear' as const,
						position: 'left' as const,
						// display: false, // Add this to hide the scale initially
						grid: {
							lineWidth: function (context: any) {
								if (
									context.tick &&
									typeof context.tick.value !== 'undefined' &&
									context.tick.value === context.scale.min
								) {
									return 3
								}
								return 1
							},
						},
						ticks: {
							callback: function (value: number | string): any {
								// Format price axis labels
								return formatNumberToString(Number(value))
							},
						},
						stack: 'candle',
						stackWeight: 3,
						beginAtZero: false,
						grace: '1%', // Optional: Adds a bit of padding around min/max
					},
					// Define 'boll-axis' and 'y-macd' similarl
					// Ensure that the x-axis for candlesticks remains visible
					x: {
						type: 'timeseries' as const,
						display: true,
						time: {
							// unit: 'day' as const,
							displayFormats: {
								second: 'HH:mm:ss',
								minute: 'HH:mm',
								hour: 'MM dd, HH:mm',
								day: 'MM dd',
								week: 'll', // Example format for weeks, adjust as needed
								month: 'MMM yy',
								quarter: '[Q]QQQ yy',
								year: 'yy',
							},
						},
						border: {
							display: false,
						},
						grid: {
							display: true,
							drawOnChartArea: true,
							drawTicks: true,
						},
						ticks: {
							minRatation: 50,
							maxRotation: 50,
							sampleSize: 10,
						},
					},
				},
				plugins: {
					legend: {
						display: false, // Disable the built-in legend
					},
					tooltip: {
						enabled: false, // Disable default tooltip if you want to handle tooltip separately
						mode: 'index' as const,
					},
					zoom: {
						zoom: {
							wheel: {
								enabled: false,
							},
							drag: {
								enabled: true,
							},
							pinch: {
								enabled: true,
							},
							mode: 'x' as const,
							scaleMode: 'x' as const,
						},
					},
					title: {
						display: false,
						text: 'Day Kline',
					},
				},
			},
		})
		updateYPriceAxisScale(candleChart, prices)
		updateAxisScale(candleChart, 'y-volume', [volumes])
		if (trade_bot.malines && trade_bot.malines.length > 0) {
			let max_shown_malines = 9
			for (let i = 0; i < max_shown_malines && i < trade_bot.malines.length; i++) {
				let gk: MaLineGroupKey = trade_bot.malines[i].gk
				let period: number = trade_bot.malines[i].period
				if (gk === 'LSMA') {
					upsertChartLsma(candleChart, klines, period, i, 'y-price')
				} else {
					upsertChartMa(candleChart, klines, gk.toLowerCase(), period, i, 'y-price')
				}
			}
		}

		// </candleChart>

		candleCanvas.addEventListener('mousemove', candleChartMousemove)

		//indicatorChart
		indicatorChart = new Chart(indicatorCanvas, {
			data: {
				datasets: [
					{
						label: 'y0',
						type: 'line' as const,
						data: [],
						yAxisID: 'y0' as const,
						backgroundColor: 'rgba(128, 0, 128, 0.3)', // Bright purple for Bollinger Bands line
						borderColor: 'rgb(128, 0, 128)', // Solid bright purple for borders
						borderWidth: 1,
						pointRadius: 0,
						fill: false,
						hoverBorderWidth: 5,
						hoverBorderColor: 'green',
					},
					{
						label: 'y1',
						type: 'line' as const,
						data: [],
						yAxisID: 'y1' as const,
						backgroundColor: 'rgba(128, 0, 128, 0.3)', // Bright purple for Bollinger Bands line
						borderColor: 'rgb(128, 0, 128)', // Solid bright purple for borders
						borderWidth: 1,
						pointRadius: 0,
						fill: false,
						hoverBorderWidth: 5,
						hoverBorderColor: 'green',
					},
					{
						label: 'y2',
						type: 'line' as const,
						data: [],
						yAxisID: 'y2' as const,
						backgroundColor: 'rgba(128, 0, 128, 0.3)', // Bright purple for Bollinger Bands line
						borderColor: 'rgb(128, 0, 128)', // Solid bright purple for borders
						borderWidth: 1,
						pointRadius: 0,
						fill: false,
						hoverBorderWidth: 5,
						hoverBorderColor: 'green',
					},
					{
						label: 'y3',
						type: 'line' as const,
						data: [],
						yAxisID: 'y3' as const,
						backgroundColor: 'rgba(128, 0, 128, 0.3)', // Bright purple for Bollinger Bands line
						borderColor: 'rgb(128, 0, 128)', // Solid bright purple for borders
						borderWidth: 1,
						pointRadius: 0,
						fill: false,
						hoverBorderWidth: 5,
						hoverBorderColor: 'green',
					},
				],
			},
			options: {
				animation: false,
				spanGaps: true, // enable for all datasets
				responsive: true,
				maintainAspectRatio: false,
				scales: {
					y0: {
						type: 'linear' as const,
						position: 'left' as const,
						// display: false, // Add this to hide the scale initially
						grid: {
							lineWidth: function (context: any) {
								if (
									context.tick &&
									typeof context.tick.value !== 'undefined' &&
									context.tick.value === context.scale.min
								) {
									return 3
								}
								return 1
							},
						},
						ticks: {
							callback: function (value: number | string): any {
								// Format price axis labels
								return formatNumberToString(Number(value))
							},
						},
						stack: 'indicator',
						stackWeight: 1,
						beginAtZero: false,
						// grace: '1%', // Optional: Adds a bit of padding around min/max
					},
					y1: {
						type: 'linear' as const,
						position: 'left' as const,
						// display: false, // Add this to hide the scale initially
						grid: {
							lineWidth: function (context: any) {
								if (
									context.tick &&
									typeof context.tick.value !== 'undefined' &&
									context.tick.value === context.scale.min
								) {
									return 3
								}
								return 1
							},
						},
						ticks: {
							callback: function (value: number | string): any {
								// Format price axis labels
								return formatNumberToString(Number(value))
							},
						},
						stack: 'indicator',
						stackWeight: 1,
						beginAtZero: false,
						grace: '1%', // Optional: Adds a bit of padding around min/max
					},
					y2: {
						type: 'linear' as const,
						position: 'left' as const,
						// display: false, // Add this to hide the scale initially
						grid: {
							lineWidth: function (context: any) {
								if (
									context.tick &&
									typeof context.tick.value !== 'undefined' &&
									context.tick.value === context.scale.min
								) {
									return 3
								}
								return 1
							},
						},
						ticks: {
							callback: function (value: number | string): any {
								// Format price axis labels
								return formatNumberToString(Number(value))
							},
						},
						stack: 'indicator',
						stackWeight: 1,
						beginAtZero: false,
						grace: '1%', // Optional: Adds a bit of padding around min/max
					},
					y3: {
						type: 'linear' as const,
						position: 'left' as const,
						// display: false, // Add this to hide the scale initially
						grid: {
							lineWidth: function (context: any) {
								if (
									context.tick &&
									typeof context.tick.value !== 'undefined' &&
									context.tick.value === context.scale.min
								) {
									return 3
								}
								return 1
							},
						},
						ticks: {
							callback: function (value: number | string): any {
								// Format price axis labels
								return formatNumberToString(Number(value))
							},
						},
						stack: 'indicator',
						stackWeight: 1,
						beginAtZero: false,
						grace: '1%', // Optional: Adds a bit of padding around min/max
					},

					x: {
						type: 'timeseries' as const,
						display: true,
						time: {
							displayFormats: {
								second: 'HH:mm:ss',
								minute: 'HH:mm',
								hour: 'MM dd, HH:mm',
								day: 'MM dd',
								week: 'll', // Example format for weeks, adjust as needed
								month: 'MMM yy',
								quarter: '[Q]QQQ yy',
								year: 'yy',
							},
						},
						border: {
							display: false,
						},
						grid: {
							display: true,
							drawOnChartArea: true,
							drawTicks: true,
						},
						ticks: {
							minRatation: 50,
							maxRotation: 50,
							sampleSize: 10,
						},
					},
				},
				plugins: {
					legend: {
						display: false, // Display the built-in legend
					},
					tooltip: {
						enabled: false, // Disable default tooltip if you want to handle tooltip separately
						mode: 'index' as const,
					},
					zoom: {
						zoom: {
							wheel: {
								enabled: false,
							},
							drag: {
								enabled: true,
							},
							pinch: {
								enabled: true,
							},
							mode: 'x' as const,
							scaleMode: 'x' as const,
						},
					},
					title: {
						display: false,
						text: 'Indicators: ADX,AROON etc.',
					},
				},
			},
		})
		if (trade_bot.indicators && trade_bot.indicators.length > 0) {
			let max_shown_indicators = 4
			for (let i = 0; i < max_shown_indicators && i < trade_bot.indicators.length; i++) {
				let gk: IndicatorGroupKey = trade_bot.indicators[i].gk
				updateIndicatorChartPart(indicatorChart, klines, gk, `y${i}`)
			}
		}

		indicatorCanvas.addEventListener('mousemove', indicatorChartMousemove)

		console.log('Chart.instance', Chart.instances)
		// Implement any data update logic here if needed
	})

	function indicatorChartMousemove(event: MouseEvent) {
		handleChartMouseMove(event, indicatorChart, tooltipElement)
	}

	function candleChartMousemove(event: MouseEvent) {
		handleChartMouseMove(event, candleChart, tooltipElement)
	}
	onDestroy(() => {
		candleCanvas.removeEventListener('mousemove', candleChartMousemove)
		indicatorCanvas.removeEventListener('mousemove', indicatorChartMousemove)
		if (candleChart) candleChart.destroy()
		if (indicatorChart) indicatorChart.destroy()
	})

	let tooltipElement: HTMLDivElement // Bind this to your tooltip div

	function initializeTooltip() {
		if (!tooltipElement) {
			console.error('Tooltip element not bound properly')
			return
		}
	}
</script>

<div class="w-full h-full grid grid-cols-6 grid-rows-18">
	<div class="row-span-17 col-span-6 px-1 bg-gray-700 text-white flex flex-col">
		<div class="w-full h-2/3 relative">
			<button
				name="resetzoom"
				class="absolute top-1 left-0 border-solid border-orange-500 border bg-orange-500 text-white text-xs px-1"
				on:click={() => {
					candleChart.resetZoom('resize')
					indicatorChart.resetZoom('resize')
				}}
			>
				Reset Zoom
			</button>
			<canvas bind:this={candleCanvas}></canvas>
		</div>
		<div class="w-full h-1/3"><canvas bind:this={indicatorCanvas}></canvas></div>
	</div>
	<div class="row-span-1 col-span-6 bg-orange-500" id="tooltipElement" bind:this={tooltipElement}>
		text content
	</div>
</div>
